﻿
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.VisualTree;
using LightCAD.Core;
using LightCAD.Runtime;
using LightCAD.Runtime.Creator;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Xml.Linq;
using System.IO.Compression;
using System.IO;
using System.Diagnostics;
using Avalonia.ReactiveUI;

namespace LightCAD.UI
{
    public class Command : ICommand
    {
        public event EventHandler? CanExecuteChanged;
        public Action<object?> Action { get; set; }

        public Command() { }

        public bool CanExecute(object? parameter)
        {
            return true;
        }

        public void Execute(object? parameter)
        {
            Action?.Invoke(parameter);
        }
    }
    public class Commands
    {

        public static void Erase()
        {
            DocumentManager.CurrentRecorder.BeginAction("ERASE");
            if (DocumentScene.SelectedElements.Count > 0)
            {
                foreach (var element in DocumentScene.SelectedElements)
                {
                    DocumentManager.Current.ModelSpace.RemoveElement(element);
                }
            }
            DocumentScene.ClearSelects();
            DocumentManager.CurrentRecorder.EndAction();
        }


        public static void DrawLine2P(object? args)
        {
            DocumentScene.ClearSelects();
            VPort.IsCreating = true;
            VPort.CurrentCreator = new LineCreator();
            VPort.CurrentCreator.Execute();
        }

        public static void DrawCircleCR(object? args)
        {
            DocumentScene.ClearSelects();
            VPort.IsCreating = true;
            VPort.CurrentCreator = new CircleCreator();
            VPort.CurrentCreator.Execute();
        }

        public static void DrawCircle2P(object? args)
        {
            DocumentScene.ClearSelects();
            VPort.IsCreating = true;
            VPort.CurrentCreator = new CircleCreator();
            VPort.CurrentCreator.Execute("2P");
        }

        internal static void DragCopy(double dragX, double dragY)
        {
            DocumentManager.CurrentRecorder.BeginAction("DRAGCOPY");
            var copyElements = new List<Element>();
            foreach (var element in DocumentScene.SelectedElements)
            {
                var copyEle = element.Clone();
                DocumentManager.Current.ModelSpace.InsertElement(copyEle);
                copyElements.Add(copyEle);
            }
            foreach (var element in copyElements)
            {
                DocumentManager.Current.ModelSpace.MoveElement(element, dragX, dragY);
            }
            DocumentScene.SetSelectsToDragging(false);
            DocumentScene.ClearSelects();
            DocumentScene.SelectElements(copyElements);

            RuntimeScene.ResetElementGrips(copyElements);
            DocumentManager.CurrentRecorder.EndAction();

        }

        internal static void Drag(double dragX, double dragY)
        {
            DocumentManager.CurrentRecorder.BeginAction("DRAGMOVE");
            foreach (var element in DocumentScene.SelectedElements)
            {
                DocumentManager.Current.ModelSpace.MoveElement(element, dragX, dragY);
            }
            RuntimeScene.ResetElementGrips(DocumentScene.SelectedElements);
            DocumentManager.CurrentRecorder.EndAction();
        }


        public static void Copy()
        {
            if (DocumentScene.SelectedElements.Count == 0) return;
            var elements = new List<Element>();
            var box = new Box2d();
            box.SetEmpty();
            foreach (var element in DocumentScene.SelectedElements)
            {
                box.Union(element.BoundingBox);
                var copyEle = element.Clone();
                elements.Add(copyEle);
            }

            foreach (var element in elements)
            {
                element.Translate(-box.Location.X, -box.Location.Y);
            }

            var dataObject = new DataObject();
            var josn = JsonSerializer.Serialize(elements);
            dataObject.Set("LightCAD_Elements", josn);
            Application.Current.Clipboard.SetDataObjectAsync(dataObject);
        }

        internal static void Cut()
        {
            if (DocumentScene.SelectedElements.Count == 0) return;
            Copy();
            DocumentManager.CurrentRecorder.BeginAction("CUT");
            foreach (var element in DocumentScene.SelectedElements)
            {
                DocumentManager.Current.ModelSpace.RemoveElement(element);
            }
            DocumentScene.ClearSelects();
            DocumentManager.CurrentRecorder.EndAction();
        }

        internal static async void Paste()
        {
            VPort.CancelAll();
            var data = await Application.Current.Clipboard.GetDataAsync("LightCAD_Elements");
            if (data == null) return;
            var json = Encoding.Unicode.GetString((byte[])data).Trim('\0');
            var elements = JsonSerializer.Deserialize<List<Element>>(json);
            if (elements.Count == 0) return;

            var box = new Box2d();
            box.SetEmpty();
            foreach (var element in elements)
            {
                box.Union(element.BoundingBox);
            }
            DocumentScene.PastingBox = box;//用于显示粘贴内容的外框，暂时无用

            DocumentScene.ClearSelects();
            DocumentScene.PastingElements = elements;
            VPort.IsPasting = true;
        }
        internal static void PasteDone()
        {
            var pointerPos = VPort.PointerPressedPosition;
            var wp = VPort.ScrToWorld(pointerPos);
            DocumentManager.CurrentRecorder.BeginAction("PASTE");
            foreach (var element in DocumentScene.PastingElements)
            {
                var copyEle = element.Clone();
                copyEle.Initilize(DocumentManager.Current);//来自剪切板的元素没有Document上下文，需初始化
                copyEle.Translate(wp.X, wp.Y);
                DocumentManager.Current.ModelSpace.InsertElement(copyEle);

            }
            DocumentManager.CurrentRecorder.EndAction();
        }
        internal static void Undo()
        {
            VPort.CancelAll();
            DocumentManager.CurrentRecorder.UndoAction();
        }
        internal static void Redo()
        {
            DocumentManager.CurrentRecorder.RedoAction();
        }


        public static void Create()
        {
            var doc = DocumentManager.Create();
            LcadApp.ActiveWindow.OpenDrawingTab(doc);
            DocumentManager.SetCurrent(doc);
        }
        public const string DrawingFileName = "drawing.json";
        public static async void Open()
        {
            var filePath = await LcadApp.ActiveWindow.OpenDrawingFile();
            if (filePath == null) return;

            var start = DateTime.Now;
            var zipFile = ZipFile.OpenRead(filePath);
            var zipDict = zipFile.Entries.ToDictionary((e) => e.FullName);
            var drawingEntry = zipDict[DrawingFileName];
            using (StreamReader reader = new StreamReader(drawingEntry.Open()))
            {
                var json = reader.ReadToEnd();
                var doc = LcDocument.FromJson(json);
                doc.FilePath = filePath;
                LcadApp.ActiveWindow.OpenDrawingTab(doc);
                DocumentManager.SetCurrent(doc);
            }
            Debug.Print("OpenFile:" + (DateTime.Now - start).TotalSeconds.ToString());
        }
        public static async void Save()
        {

            var doc = DocumentManager.Current;
            //如果是新建文档没有目录
            doc.FilePath = await LcadApp.ActiveWindow.SaveDrawingFile(doc.FilePath);

            if (doc.FilePath == null) return;

            var options = new JsonSerializerOptions
            {
                ReferenceHandler = ReferenceHandler.Preserve,
                DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
                WriteIndented = true
            };
            var start = DateTime.Now;
            using (FileStream zipFile = new FileStream(doc.FilePath, FileMode.OpenOrCreate))
            using (ZipArchive archive = new ZipArchive(zipFile, ZipArchiveMode.Create))
            {
                ZipArchiveEntry readMeEntry = archive.CreateEntry(DrawingFileName);
                using (StreamWriter writer = new StreamWriter(readMeEntry.Open()))
                {
                    var json = LcDocument.ToJson(doc, false);
                    writer.Write(json);
                }
            }
            Debug.Print("SaveFile:" + (DateTime.Now - start).TotalSeconds.ToString());

        }


    }
}
